Mockito

@VERO
Created Date · 2023년 09월 09일 05:09
Last Updated Date · 2023년 10월 15일 13:10

생성자 mock

LoginController 에서 다음과 같이 private 메서드로 세션을 생성한다.

private Session createSession(final User user) {  
    final Session session = new Session();  
    SessionManager.getInstance().add(session);  
    session.setAttribute("user", user);  
    return session;  
}

이때 세션은 생성될 때 랜덤값을 생성하기 때문에 테스트하기 매우 곤란하다.
특히 UUID 가 겹칠 일은 사람이 걸어가다가 운석 맞을 확률이라고 한다 (ㅋㅋ)

public Session() {  
    this.id = UUID.randomUUID().toString();  
}

이럴 때 mockConstruct 를 사용한다.
이렇게 해주면 모든 SessiongetId 로 1234 를 리턴하기 때문에 테스트할 수 있게 된다!

final LoginController loginController = new LoginController();  
try (final MockedConstruction<Session> sessionMockedConstruction = mockConstruction(Session.class,  
    (mock, context) -> {  
        when(mock.getId()).thenReturn("1234");  
    })  
) {  
    final ResponseEntity responseEntity = loginController.service(httpRequest);  
  
    // then  
    assertThat(responseEntity.getHeaders()  
            .containsHeaderNameAndValue(HttpHeaderName.SET_COOKIE, "JSESSIONID=1234")).isTrue();   
}

try-with-resources 를 사용하여 테스트가 끝나면 닫아준다.

생성자가 호출된 횟수 알아내기

class MyClass {
    void myMethod() {
        // do something
    }
}

@Test
public void testMyMethodInvocation() {
    try (MockedConstruction<MyClass> mocked = mockConstruction(MyClass.class)) {
        MyClass instance1 = new MyClass();
        MyClass instance2 = new MyClass();

        instance1.myMethod();
        instance2.myMethod();
        instance2.myMethod();

        // 첫 번째 생성된 객체의 myMethod 호출 횟수 확인
        verify(mocked.constructed().get(0), times(1)).myMethod();

        // 두 번째 생성된 객체의 myMethod 호출 횟수 확인
        verify(mocked.constructed().get(1), times(2)).myMethod();
    }
}

.constructed().get(x) 로 x번째로 생성된 객체의 메서드 호출 횟수를 확인할 수 있다.

⚠️ 주의 !! 리플렉션으로 동적으로 생성된 객체는 카운팅 되지 않으니 유의하자.

mockStatic

static 메서드를 모킹하고 싶을 때가 있다.
나는 싱글톤 패턴을 사용했는데, 싱글톤의 경우 mocking 을 해주기 곤란하다.
SessionManager.getInstance 에서 내가 mock 해둔 SessionManager 를 리턴해주도록 변경해야 했다.

이럴 때 mockStatic 을 사용한다.

final SessionManager sessionManager = mock(SessionManager.class);  
doNothing().when(sessionManager).validateSession(any());  
  
try (final MockedStatic<SessionManager> mockSessionManger = mockStatic(SessionManager.class)) {  
    mockSessionManger.when(SessionManager::getInstance)  
        .thenReturn(sessionManager);  
  
    // when  
    final boolean result = loginInterceptor.preHandle(loginHttpRequest, basicResponse);  
  
    // then  
    assertAll(  
        () -> assertThat(result).isFalse(),  
        () -> assertThat(basicResponse.getHeaders().getHeaderValue(HttpHeaderName.LOCATION))  
            .contains("/index.html")  
    );  
}

클래스의 static 메서드가 어떤 값을 리턴할 지 지정해줄 수 있다.
try-with-resources 로 테스트가 끝나면 닫아준다.

verify()

verify(requestDispatcher, only()).forward(any(), any());

모킹된 객체에서 메서드가 몇 번 불렸는지 확인할 수 있다. (spy 도 가능하다.)

only() 를 사용하면 단 한 번 호출되었다는 것을 확인할 수 있다.
times() 로 몇 번 호출했는지 체크할 수 있다.